package com.fcy.teamwork.base

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding


abstract class BaseRVAdapter<T, B : ViewBinding> : RecyclerView.Adapter<BaseRVAdapter.VH>() {
    companion object {
        const val VIEW_TYPE_DECORATION = -1
        const val VIEW_TYPE_FOOTER = -2
    }

    protected var source: List<T> = mutableListOf()
        private set
    protected val realLen
        get() = source.size

    class VH(root: View) : RecyclerView.ViewHolder(root) {
        lateinit var binding: ViewBinding

        constructor(binding: ViewBinding) : this(binding.root) {
            this.binding = binding
        }
    }

    var onItemClickAction: ((T) -> Any)? = null

    override fun getItemViewType(position: Int): Int {
        return if (hasFooter() && position == itemCount - 1) VIEW_TYPE_FOOTER
        else if (hasDecoration() && position % 2 != 0)
            VIEW_TYPE_DECORATION
        else position / 2
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
        val layoutInflater = LayoutInflater.from(parent.context)
        val binding = when (viewType) {
            VIEW_TYPE_FOOTER -> {
                createFootBinding(layoutInflater, parent, viewType)
            }
            VIEW_TYPE_DECORATION -> {
                createDecorationBinding(layoutInflater, parent, viewType)
            }
            else -> createBinding(layoutInflater, parent, viewType)
        }

        return VH(binding)
    }


    override fun onBindViewHolder(holder: VH, position: Int) {
        if (onItemClickAction != null)
            holder.binding.root.setOnClickListener {
                val action = onItemClickAction
                if (action != null) action(source[position])
            }
        if (hasFooter() && position == itemCount - 1) {
            bindFooterView(holder, position)
        } else if (hasDecoration()) {
            if (position % 2 == 0) {
                bindView(holder, position / 2, source[position / 2])
            } else {
                bindDecorationView(holder, position / 2)
            }
        } else {
            bindView(holder, position, source[position])
        }
    }

    override fun getItemCount(): Int {
        var itemCount = source.size
        itemCount = if (!hasDecoration()) itemCount
        else itemCount * 2 - 1
        if (hasFooter())
            itemCount++
        return itemCount
    }

    /**
     *
     * @param holder VH
     * @param position Int 所属view的position
     */
    open fun bindDecorationView(holder: VH, position: Int) {}
    open fun bindFooterView(holder: VH, position: Int) {}
    abstract fun createBinding(inflater: LayoutInflater, parent: ViewGroup, viewType: Int): B
    abstract fun bindView(holder: VH, position: Int, data: T)

    open fun hasFooter(): Boolean = false
    open fun createFootBinding(
        inflater: LayoutInflater,
        parent: ViewGroup,
        viewType: Int
    ): ViewBinding {
        throw Exception("设置了footer 没有重写foot的view构造方法")
    }

    open fun createDecorationBinding(
        inflater: LayoutInflater,
        parent: ViewGroup,
        viewType: Int
    ): ViewBinding {
        throw Exception("设置了Decoration 没有重写Decoration的view构造方法")
    }

    @SuppressLint("NotifyDataSetChanged")
    fun submitData(data: List<T>): Int {
        source = data
        notifyDataSetChanged()
        return source.size - 1
    }

    fun insertData(item: T): Int {
        source = ArrayList(source).apply {
            add(item)
        }
        val position = source.size - 1
        notifyItemInserted(position)
        return position
    }

    fun insertData(items: List<T>): Int {
        if (items.isEmpty())
            return source.size - 1
        val count = items.size
        val startPosition = source.size - 1
        source = ArrayList(source).apply {
            addAll(items)
        }
        notifyItemRangeInserted(startPosition, count)
        return source.size - 1
    }


    open fun hasDecoration() = false
}